﻿/*
 * Twipler - Twitter Web Client with features.
 *  
 *  Copyright (C) 2009, 2010. Ian Quigley
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details. 
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 */

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Web;
using System.IO;
using Newtonsoft.Json;
using Twipler.App.Session;

namespace Twipler.App.DataDoc
{
    public class DataDocJson : DataDocList
    {
		
		private string _originalContent;
		
    	public DataDocJson(Func<string> content)
		{
    		try
            {
				_originalContent = content();

				if (IsFailWhale(_originalContent))
				{
					Document = new List<DataDocValue>() { new DataDocValue("response_status", "error"), new DataDocValue("error", FailWhale(_originalContent)) };
					_status = DataDocStatus.TwitterError;
					_originalContent = "{\"response_status\" : \"error\", \"message\" : \"Twitter is too busy to respond\"}"; 
				}
				else
				{
					using (JsonTextReader reader = new JsonTextReader(new StringReader(_originalContent)))
						Document = GetAll(reader);

					bool errors = (Find("/errors") != null);
					bool error = (Find("/error") != null);
					if (errors || error)
					{
						var message = error ? Find("/error") : Find("/errors/0/message");
						Document = new List<DataDocValue>() {new DataDocValue("response_status", "error"), message};
						_status = DataDocStatus.TwitterError;
						_originalContent = "{\"response_status\" : \"error\", \"message\" : \"" + message + "\"}";
					}

				}
            }
            catch (Exception ex)
            {
                Current.Log.Fatal("Exception: " + ex.Message);
                Twipler.WebApp.ExceptionReport.Report(ex);
				
            	Document = new List<DataDocValue>() {new DataDocValue("response_status", "error"), new DataDocValue("error", ex.Message)};
                _status = DataDocStatus.TwitterError;
				_originalContent = "{\"response_status\" : \"error\", \"message\" : \"" + ex.Message + "\"}";
            }
        }

        private string FailWhale(string contentText)
        {
            int titleStart = contentText.IndexOf("<title>");
            int titleEnd = contentText.IndexOf("</title>");

            return (titleStart != -1 && titleEnd != -1 && titleStart < titleEnd)
					? contentText.Substring(titleStart + "<title>".Length, titleEnd - titleStart - "</title>".Length)
					: "Unknown";
        }

        private static bool IsFailWhale(string contentText)
        {
            return (contentText.StartsWith("<!DOCTYPE"));                
        }

        private static List<DataDocValue> GetAll(JsonReader reader)
        {
            List<DataDocValue> values = new List<DataDocValue>();
            Stack<List<DataDocValue>> listStack = new Stack<List<DataDocValue>>();

            string name = string.Empty;
            Stack<string> nameStack = new Stack<string>();

            while (reader.Read())
            {
                switch (reader.TokenType)
                {
                    case JsonToken.PropertyName:
                        name = reader.Value.ToString();
                        break;

                    case JsonToken.StartConstructor:
                    case JsonToken.EndConstructor:
                        continue;

                    case JsonToken.StartObject:
                    case JsonToken.StartArray:
                        listStack.Push(values);
                        nameStack.Push(name);
                        values = new List<DataDocValue>();
                        name = "0";
                        break;

                    case JsonToken.EndObject:
                    case JsonToken.EndArray:
                        List<DataDocValue> array = values;
                        values = listStack.Pop();
                        name = nameStack.Pop();
                        values.Add(new DataDocValue(name, array));
                        name = values.Count().ToString();
                        break;
                        
                    default:
                        values.Add(new DataDocValue(name, reader.Value));
                        name = values.Count().ToString();
                        break;
                }
            }

            return values;
        }

    	public override string ToString()
    	{
    		return _originalContent;
    	}
    }


}